
/**
 * @file log.c
 * @author fishmwei <fishmwei@qq.com>
 * @brief 
 *
 * @copyright
 * Copyright All Reserved
 *
 * This source code is licensed under BSD 3-Clause License (the "License").
 * You may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     https://opensource.org/licenses/BSD-3-Clause
 */

#define _GNU_SOURCE

#include <sys/cdefs.h>
#include <assert.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <syslog.h>

#include "common.h"
#include "log.h"


clog_log_level_t stderr_ll = CLOG_LL_NONE;  /**< stderr log level */

#ifdef CLOG_SYSLOG
clog_log_level_t syslog_ll = CLOG_LL_NONE;  /**< syslog log level */
int syslog_open;                            /**< Whether syslog was opened */
#endif

clog_log_cb log_cb;                       /**< Logging callback */

void clog_log_msg(int plugin, clog_log_level_t ll, const char *msg)
{
    int priority = 0;
    const char *severity = NULL;

    switch (ll) 
    {
    case CLOG_LL_ERR:
        priority = LOG_ERR;
        severity = "ERR";
        break;
    case CLOG_LL_WRN:
        priority = LOG_WARNING;
        severity = "WRN";
        break;
    case CLOG_LL_INF:
        priority = LOG_INFO;
        severity = "INF";
        break;
    case CLOG_LL_DBG:
        priority = LOG_DEBUG;
        severity = "DBG";
        break;
    case CLOG_LL_NONE:
        assert(0);
        return;
    }

    /* stderr logging */
    if (ll <= stderr_ll) 
    {
        fprintf(stderr, "[%s]:%s %s\n", severity, plugin ? " plugin:" : "", msg);
    }

#ifdef CLOG_SYSLOG
    /* syslog logging */
    if (ll <= syslog_ll) 
    {
        syslog(priority | (plugin ? LOG_DAEMON : 0), "[%s] %s\n", severity, msg);
    }
#endif

    /* logging callback */
    if (log_cb) 
    {
        log_cb(ll, msg);
    }
}
   

API void clog_log(clog_log_level_t ll, const char *format, ...)
{
    va_list ap;
    char *msg;
    int msg_len = 0;

    va_start(ap, format);
    clog_vsprintf(&msg, &msg_len, 0, format, ap);
    va_end(ap);

    clog_log_msg(0, ll, msg);
    free(msg);
}

API void clog_log_stderr(clog_log_level_t log_level)
{
    stderr_ll = log_level;
}

API clog_log_level_t clog_log_get_stderr(void)
{
    return stderr_ll;
}

#ifdef CLOG_SYSLOG
API void clog_log_syslog(const char *app_name, clog_log_level_t log_level)
{
    syslog_ll = log_level;

    if ((log_level > CLOG_LL_NONE) && !syslog_open) 
    {
        openlog(app_name ? app_name : "clog", LOG_CONS | LOG_PID | LOG_NDELAY, LOG_USER);

        syslog_open = 1;
    } 
    else if ((log_level == CLOG_LL_NONE) && syslog_open) 
    {
        closelog();

        syslog_open = 0;
    }
}

API clog_log_level_t clog_log_get_syslog(void)
{
    return syslog_ll;
}

#endif

API void clog_log_set_cb(clog_log_cb log_callback)
{
    log_cb = log_callback;
}
